/*
 * FIRC: A IRC Client for Flash Player 9 and above
 * Copyright (C) 2005-2006 Darron Schall <darron@darronschall.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 */
package irc
{
	import flash.events.*;
	import flash.net.Socket;
	import events.*;
	import mx.controls.Alert;
	import mx.controls.Text;
	import flash.errors.EOFError;
	import mx.utils.StringUtil;
	import mx.messaging.events.MessageEvent;
	import flash.display.JointStyle;
	import flash.utils.*;
	
	public class IRCProtocol extends Socket
	{
		/** The port we're connecting on */
		private var port:uint;
	
		/** The host we're connecting to */
		private var host:String;

		/** The host we're connecting to */
		public var nick:String;
		
		
		/** The buffer for received messages */
		private var buffer:String;	
		
			
		/**
		* Constructor, creates a new RFB socket connection to a host
		* on a specific port.
		*/
		public function IRCProtocol( host:String, port:uint, nick:String)
		{
			super( host, port );
			this.host = host;
			this.port = port;
			this.nick = nick;
			buffer="";
						
		}
		
		/**
		* Register nickname
		*/
		public function RegisterNick():void 
		{
			//writeUTFBytes("PASS toto \r\n");
			WriteRawMessage("NICK " + nick);
			WriteRawMessage("USER " + nick + " host server :Test firc");
			flush();
		}
		
		/**
		 * 
		 * Decode messages from the server
		 * 
		 */		
		public function ReadMessage():void 
		{
			try {
				buffer += readUTFBytes(bytesAvailable);
				var buferTmp:String = new String(buffer);
				var indx:int = buffer.lastIndexOf("\r\n");
				if(indx > -1) {
					buffer = buffer.substring(indx+2);
					for each(var mess:String in buferTmp.substring(0,indx).split("\r\n")) {
						decodeMessage(mess);
					}
				}
			}
			catch ( e:EOFError )
			{			
			}	
		}
		
		private function decodeMessage(mess:String):void
		{
				mess = StringUtil.trim(mess);
				trace("< " + mess);
				if(mess == "") return;
				//auto reply pong
				if(mess.substr(0,6) == "PING :") 
				{
					WriteRawMessage("PONG " + mess.substr(6,mess.length-6));
				}
				
				
				/*
			     * From RFC 1459:
				 *  <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
				 *  <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
				 *  <command>  ::= <letter> { <letter> } | <number> <number> <number>
				 *  <SPACE>    ::= ' ' { ' ' }
				 *  <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
				 *  <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
				 *                 or NUL or CR or LF, the first of which may not be ':'>
				 *  <trailing> ::= <Any, possibly *empty*, sequence of octets not including
				 *                   NUL or CR or LF>
				*/
				
				//parse Previx
				if(mess.charAt(0) == ':') {
					var re1:RegExp = new RegExp("[ @!]");
					var prefix:String = mess.split(re1)[0].substring(1);
					mess = mess.substring(mess.indexOf(" ")+1);
				}
				
				//parse commande / code
				var cmd:String;
			 	cmd = mess.split(" ",1)[0];
			 	mess = mess.substring(mess.indexOf(" ")+1);
			 	if(cmd == "004") dispatchEvent(new ConnectedEvent());
			 
			 	//parse params
			 	var params:Array;
				if(mess.indexOf(":") > -1) {
			 		params = mess.split(":")[0].split(" ")
					if(params[params.length-1] == "")
			 		params[params.length-1] = mess.substring(mess.indexOf(":")+1);
			 		else params = params.concat(mess.substring(mess.indexOf(":")+1));
				}
				else {
					params = mess.split(" ");
				}
				var me:RecvMessageEvent = new RecvMessageEvent(prefix,cmd,params);
				dispatchEvent(me);	
		}
		
		
		/**
		 * Send a raw message to the server
		 */
		public function WriteRawMessage(mess:String):void
		{
			trace("> " + mess);
			writeUTFBytes(mess + "\r\n");
			flush();
		}
	
		
		/**
		 * Send a message to the server
		 */
		public function WriteMessage(chanID:String, mess:String):void
		{
			var mess2Serv:String = "";
			mess = StringUtil.trim(mess);
			//Commands
			if(mess.charAt(0) == '/')
			{
				var tok:Array = mess.split(' ');
				var cmd:String = tok[0].toLowerCase();
				switch(cmd) {
					case "/j" :
					case "/join" :
						join(tok.slice(1).join(" "));
						return;	
					case "/part" :	
						mess2Serv = "PART ";
						mess2Serv += tok.slice(1).join(" ");
						break;
					case "/quit" :	
						mess2Serv = "QUIT ";
						mess2Serv += tok.slice(1).join(" ");
						break; 
					case "/notice" :	
						mess2Serv = "NOTICE ";
						mess2Serv += tok.slice(1).join(" ");
						break;
					case "/me" :	
						mess2Serv = "PRIVMSG " + chanID + " :\x01ACTION";
						mess2Serv += mess.substring(cmd.length);
						mess2Serv += "\x01";
						break;
					case "/op" :	
						mess2Serv = "MODE " + chanID + " +o ";
						if(tok[1]) mess2Serv += tok[1];
						else return;
						break;
					case "/voice" :	
						mess2Serv = "MODE " + chanID + " +v ";
						if(tok[1]) mess2Serv += tok[1];
						else return;
						break;
					case "/deop" :	
						mess2Serv = "MODE " + chanID + " -o ";
						if(tok[1]) mess2Serv += tok[1];
						else return;
						break;
					case "/devoice" :	
						mess2Serv = "MODE " + chanID + " -v ";
						if(tok[1]) mess2Serv += tok[1];
						else return;
						break;
					default :
						WriteRawMessage(mess.substr(1));
						return;
					break;
				}
			}
			else mess2Serv += "PRIVMSG " + chanID + " :" + mess;
			trace("> " + mess2Serv);
			writeUTFBytes(mess2Serv + "\r\n");			
			flush();
		}
		
		public function join(chanID:String):void {
			var temp:String = StringUtil.trim(chanID);
			if(temp.charAt(0) != "#") {
				temp = "#" + temp;
			}
			WriteRawMessage("JOIN " +	temp);
			WriteRawMessage("MODE " +	temp);
		}
	}
}
